using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MT5Trade.Models;
using NLog;

namespace MT5Trade.Tests.TestFramework
{
    /// <summary>
    /// 测试验证器 - 提供通用的测试验证逻辑
    /// 遵循 generic-rule.md 规则 #168：禁止硬编码测试数据
    /// </summary>
    public class TestValidator
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private readonly double _tolerance;

        public TestValidator(double tolerance = 0.01)
        {
            _tolerance = tolerance;
        }

        /// <summary>
        /// 验证Kelly公式计算结果
        /// 复杂度: O(1)
        /// </summary>
        public ValidationResult ValidateKellyFormula(
            double actualGap,
            double expectedGap,
            double mainLossProbability,
            double expectedMove,
            double spread,
            string scenarioName)
        {
            var result = new ValidationResult
            {
                ScenarioName = scenarioName,
                TestType = "Kelly Formula"
            };

            try
            {
                // 验证gap在合理范围内 (5%-25%)
                if (actualGap < 0.05 || actualGap > 0.25)
                {
                    result.IsValid = false;
                    result.ErrorMessage = $"Gap {actualGap:P} 超出合理范围 [5%, 25%]";
                    return result;
                }

                // 验证相对误差
                var relativeError = Math.Abs(actualGap - expectedGap) / expectedGap;
                result.IsValid = relativeError <= _tolerance;

                if (!result.IsValid)
                {
                    result.ErrorMessage = $"相对误差 {relativeError:P} 超过容忍度 {_tolerance:P}";
                }

                // 验证Kelly公式的约束条件
                // f* = (p*b - q) / b，其中对于反向交易：
                // p = 1 - mainLossProbability (跟单账户盈利概率)
                // q = mainLossProbability (跟单账户亏损概率)
                var p = 1 - mainLossProbability;
                var q = mainLossProbability;
                var b = (expectedMove - spread) / spread; // 赔率

                // Kelly值应该为正（有利可图的情况）
                var kellyNumerator = p * b - q;
                if (kellyNumerator <= 0 && actualGap > 0.05)
                {
                    result.Warnings.Add($"Kelly公式分子为负 ({kellyNumerator:F4})，但仍建议 {actualGap:P} 的gap");
                }

                result.ActualValue = actualGap;
                result.ExpectedValue = expectedGap;
                result.Metrics["RelativeError"] = relativeError;
                result.Metrics["KellyNumerator"] = kellyNumerator;
                result.Metrics["PayoffRatio"] = b;

                Logger.Debug($"Kelly验证 - 场景: {scenarioName}, 实际: {actualGap:P}, " +
                           $"期望: {expectedGap:P}, 误差: {relativeError:P}");

                return result;
            }
            catch (Exception ex)
            {
                result.IsValid = false;
                result.ErrorMessage = $"验证失败: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// 验证GARCH模型波动率预测
        /// 复杂度: O(n) where n = 历史数据点数
        /// </summary>
        public ValidationResult ValidateGARCHPrediction(
            double predictedVolatility,
            List<double> historicalReturns,
            double omega,
            double alpha,
            double beta,
            string scenarioName)
        {
            var result = new ValidationResult
            {
                ScenarioName = scenarioName,
                TestType = "GARCH Model"
            };

            try
            {
                // GARCH(1,1): σ²_t = ω + α*ε²_{t-1} + β*σ²_{t-1}
                // 验证参数约束
                if (alpha < 0 || beta < 0 || alpha + beta >= 1)
                {
                    result.IsValid = false;
                    result.ErrorMessage = $"GARCH参数违反约束: α={alpha}, β={beta}, α+β={alpha + beta}";
                    return result;
                }

                // 计算实际波动率（用于对比）
                var actualVolatility = CalculateHistoricalVolatility(historicalReturns);

                // 验证预测波动率的合理性
                var volatilityRatio = predictedVolatility / actualVolatility;
                result.IsValid = volatilityRatio > 0.5 && volatilityRatio < 2.0; // 预测应在历史波动率的50%-200%范围内

                if (!result.IsValid)
                {
                    result.ErrorMessage = $"预测波动率 {predictedVolatility:F4} 与历史波动率 {actualVolatility:F4} 差异过大";
                }

                result.ActualValue = predictedVolatility;
                result.ExpectedValue = actualVolatility;
                result.Metrics["VolatilityRatio"] = volatilityRatio;
                result.Metrics["Persistence"] = alpha + beta;
                result.Metrics["LongRunVariance"] = omega / (1 - alpha - beta);

                Logger.Debug($"GARCH验证 - 场景: {scenarioName}, 预测: {predictedVolatility:F4}, " +
                           $"历史: {actualVolatility:F4}, 持续性: {alpha + beta:F4}");

                return result;
            }
            catch (Exception ex)
            {
                result.IsValid = false;
                result.ErrorMessage = $"GARCH验证失败: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// 验证VaR风险计算
        /// 复杂度: O(n log n) due to sorting for percentile
        /// </summary>
        public ValidationResult ValidateVaRCalculation(
            double calculatedVaR,
            List<double> returns,
            double confidenceLevel,
            string scenarioName)
        {
            var result = new ValidationResult
            {
                ScenarioName = scenarioName,
                TestType = "VaR Calculation"
            };

            try
            {
                // 使用历史模拟法验证VaR
                var sortedReturns = returns.OrderBy(r => r).ToList();
                var percentileIndex = (int)((1 - confidenceLevel) * sortedReturns.Count);
                var historicalVaR = Math.Abs(sortedReturns[percentileIndex]);

                // 验证计算的VaR与历史VaR的一致性
                var varRatio = calculatedVaR / historicalVaR;
                result.IsValid = varRatio > 0.8 && varRatio < 1.2; // 允许20%的差异

                if (!result.IsValid)
                {
                    result.ErrorMessage = $"VaR计算 {calculatedVaR:F4} 与历史VaR {historicalVaR:F4} 差异过大";
                }

                // Kupiec回测 (LR test)
                var violations = returns.Count(r => r < -calculatedVaR);
                var expectedViolations = returns.Count * (1 - confidenceLevel);
                var kupiecStatistic = CalculateKupiecStatistic(violations, expectedViolations, returns.Count);

                result.ActualValue = calculatedVaR;
                result.ExpectedValue = historicalVaR;
                result.Metrics["VaRRatio"] = varRatio;
                result.Metrics["Violations"] = violations;
                result.Metrics["ExpectedViolations"] = expectedViolations;
                result.Metrics["KupiecStatistic"] = kupiecStatistic;

                // Kupiec test: χ²(1) critical value at 95% = 3.84
                if (kupiecStatistic > 3.84)
                {
                    result.Warnings.Add($"Kupiec测试失败: 统计量 {kupiecStatistic:F2} > 3.84");
                }

                Logger.Debug($"VaR验证 - 场景: {scenarioName}, 计算: {calculatedVaR:F4}, " +
                           $"历史: {historicalVaR:F4}, 违规次数: {violations}/{expectedViolations:F1}");

                return result;
            }
            catch (Exception ex)
            {
                result.IsValid = false;
                result.ErrorMessage = $"VaR验证失败: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// 验证动态调整逻辑
        /// </summary>
        public ValidationResult ValidateDynamicAdjustment(
            double adjustedGap,
            double baseGap,
            double performanceScore,
            double volatilityRatio,
            string scenarioName)
        {
            var result = new ValidationResult
            {
                ScenarioName = scenarioName,
                TestType = "Dynamic Adjustment"
            };

            try
            {
                // 验证调整幅度的合理性
                var adjustmentRatio = adjustedGap / baseGap;

                // 性能好时应增加gap，性能差时应减少
                if (performanceScore > 1.0 && adjustmentRatio <= 1.0)
                {
                    result.Warnings.Add("性能良好但gap未增加");
                }
                else if (performanceScore < 1.0 && adjustmentRatio >= 1.0)
                {
                    result.Warnings.Add("性能不佳但gap未减少");
                }

                // 高波动时应减少gap
                if (volatilityRatio > 1.2 && adjustmentRatio > 1.0)
                {
                    result.Warnings.Add("高波动环境但gap增加");
                }

                // 调整后的gap仍需在合理范围内
                result.IsValid = adjustedGap >= 0.05 && adjustedGap <= 0.25;

                if (!result.IsValid)
                {
                    result.ErrorMessage = $"调整后的gap {adjustedGap:P} 超出范围 [5%, 25%]";
                }

                result.ActualValue = adjustedGap;
                result.ExpectedValue = baseGap;
                result.Metrics["AdjustmentRatio"] = adjustmentRatio;
                result.Metrics["PerformanceScore"] = performanceScore;
                result.Metrics["VolatilityRatio"] = volatilityRatio;

                Logger.Debug($"动态调整验证 - 场景: {scenarioName}, 基础: {baseGap:P}, " +
                           $"调整后: {adjustedGap:P}, 调整比率: {adjustmentRatio:F2}");

                return result;
            }
            catch (Exception ex)
            {
                result.IsValid = false;
                result.ErrorMessage = $"动态调整验证失败: {ex.Message}";
                return result;
            }
        }

        /// <summary>
        /// 批量验证测试结果
        /// </summary>
        public async Task<BatchValidationResult> ValidateBatchAsync(
            List<ValidationResult> individualResults)
        {
            var batchResult = new BatchValidationResult
            {
                TotalTests = individualResults.Count,
                PassedTests = individualResults.Count(r => r.IsValid),
                FailedTests = individualResults.Count(r => !r.IsValid)
            };

            batchResult.PassRate = (double)batchResult.PassedTests / batchResult.TotalTests;

            // 按测试类型分组统计
            var typeGroups = individualResults.GroupBy(r => r.TestType);
            foreach (var group in typeGroups)
            {
                var typeStats = new TestTypeStatistics
                {
                    TestType = group.Key,
                    Count = group.Count(),
                    Passed = group.Count(r => r.IsValid),
                    Failed = group.Count(r => !r.IsValid),
                    AverageMetrics = new Dictionary<string, double>()
                };

                // 计算平均指标
                var allMetrics = group.SelectMany(r => r.Metrics.Keys).Distinct();
                foreach (var metric in allMetrics)
                {
                    var values = group.Where(r => r.Metrics.ContainsKey(metric))
                                     .Select(r => r.Metrics[metric]);
                    if (values.Any())
                    {
                        typeStats.AverageMetrics[metric] = values.Average();
                    }
                }

                batchResult.TypeStatistics[group.Key] = typeStats;
            }

            // 收集所有警告
            batchResult.AllWarnings = individualResults
                .SelectMany(r => r.Warnings)
                .Distinct()
                .ToList();

            // 失败的测试详情
            batchResult.FailedScenarios = individualResults
                .Where(r => !r.IsValid)
                .Select(r => new FailedScenarioDetail
                {
                    ScenarioName = r.ScenarioName,
                    TestType = r.TestType,
                    ErrorMessage = r.ErrorMessage,
                    ActualValue = r.ActualValue,
                    ExpectedValue = r.ExpectedValue
                })
                .ToList();

            Logger.Info($"批量验证完成: {batchResult.PassedTests}/{batchResult.TotalTests} 通过 " +
                       $"(通过率: {batchResult.PassRate:P})");

            return await Task.FromResult(batchResult);
        }

        // 辅助方法

        private double CalculateHistoricalVolatility(List<double> returns)
        {
            if (returns.Count < 2) return 0;

            var mean = returns.Average();
            var sumSquaredDeviations = returns.Sum(r => Math.Pow(r - mean, 2));
            var variance = sumSquaredDeviations / (returns.Count - 1);
            return Math.Sqrt(variance);
        }

        private double CalculateKupiecStatistic(int violations, double expectedViolations, int sampleSize)
        {
            if (violations == 0 || violations == sampleSize) return double.MaxValue;

            var p = expectedViolations / sampleSize;
            var likelihood = -2 * Math.Log(
                Math.Pow(1 - p, sampleSize - violations) * Math.Pow(p, violations) /
                (Math.Pow(1 - (double)violations / sampleSize, sampleSize - violations) *
                 Math.Pow((double)violations / sampleSize, violations))
            );

            return likelihood;
        }
    }

    /// <summary>
    /// 验证结果
    /// </summary>
    public class ValidationResult
    {
        public string ScenarioName { get; set; }
        public string TestType { get; set; }
        public bool IsValid { get; set; }
        public string ErrorMessage { get; set; }
        public double ActualValue { get; set; }
        public double ExpectedValue { get; set; }
        public Dictionary<string, double> Metrics { get; set; } = new Dictionary<string, double>();
        public List<string> Warnings { get; set; } = new List<string>();
    }

    /// <summary>
    /// 批量验证结果
    /// </summary>
    public class BatchValidationResult
    {
        public int TotalTests { get; set; }
        public int PassedTests { get; set; }
        public int FailedTests { get; set; }
        public double PassRate { get; set; }
        public Dictionary<string, TestTypeStatistics> TypeStatistics { get; set; } = new Dictionary<string, TestTypeStatistics>();
        public List<string> AllWarnings { get; set; } = new List<string>();
        public List<FailedScenarioDetail> FailedScenarios { get; set; } = new List<FailedScenarioDetail>();
    }

    /// <summary>
    /// 测试类型统计
    /// </summary>
    public class TestTypeStatistics
    {
        public string TestType { get; set; }
        public int Count { get; set; }
        public int Passed { get; set; }
        public int Failed { get; set; }
        public Dictionary<string, double> AverageMetrics { get; set; }
    }

    /// <summary>
    /// 失败场景详情
    /// </summary>
    public class FailedScenarioDetail
    {
        public string ScenarioName { get; set; }
        public string TestType { get; set; }
        public string ErrorMessage { get; set; }
        public double ActualValue { get; set; }
        public double ExpectedValue { get; set; }
    }
}